package com.javen.controller;

import com.javen.entites.CommonResult;
import com.javen.entites.Order;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Javen
 */
@RestController
@Slf4j
public class OrderController {
    @Value("${server.port}")
    private String serverPort;

    /**
     * 服务发现，需要添加注解 @EnableDiscoveryClient
     */
    @Resource
    private DiscoveryClient discoveryClient;

    @PostMapping(value = "/order/create")
    public CommonResult create(@RequestBody Order order) {
        log.info("请求参数 {}", order);
        return new CommonResult(200, "success", serverPort);
    }

    @GetMapping(value = "/order/get/{id}")
    public CommonResult get(@PathVariable("id") Long id) {
        int tempId = 100;
        if (id == tempId) {
            return new CommonResult(500, "模拟错误信息，查询 ID: " + id, serverPort);
        } else {
            return new CommonResult(200, "success", serverPort);
        }
    }

    // 大量失败后服务熔断一段时间会恢复链路调用 (10s 内请求10次有60%失败就进行服务熔断处理)
    // https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.2.2.RELEASE/reference/html/#circuit-breaker-hystrix-clients
    // command + Shift + N 搜索 HystrixCommandProperties
    @HystrixCommand(fallbackMethod = "testHystrixFallback", commandProperties = {
            // 是否开启断路器
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
            // 请求次数
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            // 时间窗口期 10s
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
            // 失败率达到多少后跳闸
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),
    })
    @GetMapping(value = "/order/hystrix/{id}")
    public CommonResult testHystrix(@PathVariable("id") Long id) {
        int tempId = 500;
        if (id > tempId) {
            throw new RuntimeException("自定义异常");
        } else {
            return new CommonResult(200, "success", serverPort);
        }
    }

    @HystrixCommand(fallbackMethod = "timeOutHandler", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
    })
    @GetMapping("/order/hystrix/timeout/{id}")
    public CommonResult timeOut(@PathVariable("id") Long id) {
        try {
            TimeUnit.MILLISECONDS.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new CommonResult(200, serverPort + " 线程名称: " + Thread.currentThread().getName(), id);
    }

    public CommonResult timeOutHandler(Long id) {
        log.info(serverPort + " 线程名称: " + Thread.currentThread().getName() + " 系统繁忙请稍后再试 id:" + id);
        return new CommonResult(500, serverPort + " 线程名称: " + Thread.currentThread().getName() + " 系统繁忙请稍后再试 ", id);
    }

    public CommonResult testHystrixFallback(Long id) {
        log.info(serverPort + " 线程名称: " + Thread.currentThread().getName() + " 编号不能大于 500，请稍后再试 id:" + id);
        return new CommonResult(500, serverPort + " 线程名称: " + Thread.currentThread().getName() + " 编号不能大于 500，请稍后再试 id:" + id);
    }

    @GetMapping(value = "/order/discovery")
    public Object discovery() {
        // 获取所有的微服务
        List<String> services = discoveryClient.getServices();
        for (String element : services) {
            log.info("services item: {}", element);

            // 通过微服务名称获取所有提供服务的实例
            List<ServiceInstance> instances = discoveryClient.getInstances(element.toUpperCase());
            for (ServiceInstance instance : instances) {
                log.info("服务名称 {},服务 IP {},服务端口 {},服务 URI {}",
                        instance.getServiceId(), instance.getHost(),
                        instance.getPort(), instance.getUri());
            }
        }

        return this.discoveryClient;
    }
}
